package ink.xiaobaibai.service.monthly.impl;

import ink.xiaobaibai.common.TimedTask;
import ink.xiaobaibai.common.delay.DeviceDelayItemByTimedTask;
import ink.xiaobaibai.common.delay.MyDelayQueue;
import ink.xiaobaibai.entity.BuyTimedTask;
import ink.xiaobaibai.entity.MonthlyTimedTask;
import ink.xiaobaibai.service.IBuyTimedTaskService;
import ink.xiaobaibai.service.IMonthlyTimedTaskService;
import ink.xiaobaibai.service.monthly.IDelayTimedTaskService;
import ink.xiaobaibai.serviceOxy.buy.IDeviceBuyControlService;
import ink.xiaobaibai.serviceOxy.monthly.IDeviceMonControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @description: 月费定时任务实现类
 * @author: 小白白
 * @create: 2021-06-03
 **/

@Service
public class DelayTimedTaskServiceImpl implements IDelayTimedTaskService, ApplicationRunner {

    @Autowired
    private IBuyTimedTaskService buyTimedTaskService;

    @Autowired
    private IMonthlyTimedTaskService timedTaskService;

    @Autowired
    private IDeviceMonControlService deviceMonControlService;

    @Autowired
    private IDeviceBuyControlService deviceBuyControlService;

    // 已经ShutdownProtectionService保护
    public MyDelayQueue<DeviceDelayItemByTimedTask> delayQueue = new MyDelayQueue<>();

    @Override
    public void initTodayTimedTask() {
        //开启且可用的机器
        List<MonthlyTimedTask> list = this.timedTaskService.getCanUseDeviceTimedTask();
        List<DeviceDelayItemByTimedTask> delayItemList = list.stream().map(DeviceDelayItemByTimedTask::new).collect(Collectors.toList());
        this.delayQueue.addAll(delayItemList);
    }

    @Override
    public void openTimeTask(MonthlyTimedTask monthlyTimedTask) {
        if (monthlyTimedTask.getOpen()) {
            return;
        }
        TimedTask timedTask = monthlyTimedTask.getTimedTask();
        List<TimedTask.TimeNode> timeNodeList = timedTask.getTimeNodeList();
        //去除已经溜过去的任务
        Date date = new Date();
        Iterator<TimedTask.TimeNode> iterator = timeNodeList.iterator();
        while (iterator.hasNext()) {
            TimedTask.TimeNode next = iterator.next();
            if (next.getEndTime().getTime() < date.getTime()) {
                iterator.remove();
            } else {
                break;
            }
        }
        DeviceDelayItemByTimedTask delayItemByTimedTask = new DeviceDelayItemByTimedTask(monthlyTimedTask);
        this.delayQueue.add(delayItemByTimedTask);
        monthlyTimedTask.setOpen(true);
        this.timedTaskService.updateById(monthlyTimedTask);
    }

    @Override
    public void closeTimeTask(MonthlyTimedTask monthlyTimedTask) {
        if (!monthlyTimedTask.getOpen()) {
            return;
        }
        DeviceDelayItemByTimedTask delayItemByTimedTask = new DeviceDelayItemByTimedTask(monthlyTimedTask);
        this.delayQueue.remove(delayItemByTimedTask);
        monthlyTimedTask.setOpen(false);
        this.timedTaskService.updateById(monthlyTimedTask);
        this.deviceMonControlService.closeDeviceAtOnce(monthlyTimedTask.getDeviceId());
    }

    @Override
    public void initBuyTodayTimedTask() {
        List<BuyTimedTask> list = this.buyTimedTaskService.getCanUseDeviceTimedTask();
        List<DeviceDelayItemByTimedTask> delayItemList = list.stream().map(DeviceDelayItemByTimedTask::new).peek(f -> f.isBuyTime(true)).collect(Collectors.toList());
        this.delayQueue.addAll(delayItemList);
    }

    @Override
    public void openBuyTimeTask(BuyTimedTask buyTimedTask) {
        if (buyTimedTask.getOpen()) {
            return;
        }
        TimedTask timedTask = buyTimedTask.getTimedTask();
        List<TimedTask.TimeNode> timeNodeList = timedTask.getTimeNodeList();
        //去除已经溜过去的任务
        Date date = new Date();
        Iterator<TimedTask.TimeNode> iterator = timeNodeList.iterator();
        while (iterator.hasNext()) {
            TimedTask.TimeNode next = iterator.next();
            if (next.getEndTime().getTime() < date.getTime()) {
                iterator.remove();
            } else {
                break;
            }
        }
        DeviceDelayItemByTimedTask delayItemByTimedTask = new DeviceDelayItemByTimedTask(buyTimedTask);
        delayItemByTimedTask.isBuyTime(true);
        this.delayQueue.add(delayItemByTimedTask);
        buyTimedTask.setOpen(true);
        this.buyTimedTaskService.updateById(buyTimedTask);
    }

    @Override
    public void closeBuyTimeTask(BuyTimedTask buyTimedTask) {
        if (!buyTimedTask.getOpen()) {
            return;
        }
        DeviceDelayItemByTimedTask delayItemByTimedTask = new DeviceDelayItemByTimedTask(buyTimedTask);
        this.delayQueue.remove(delayItemByTimedTask);
        buyTimedTask.setOpen(false);
        this.buyTimedTaskService.updateById(buyTimedTask);
        this.deviceBuyControlService.close(buyTimedTask.getDeviceId());
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            while (true) {
                try {
                    DeviceDelayItemByTimedTask item = (DeviceDelayItemByTimedTask) this.delayQueue.take();
                    if (!item.isBuyTime()) {
                        //包月的
                        Integer openMin = item.getOpenMin();
                        this.deviceMonControlService.openDevice(item.getDeviceId(), openMin * 60);
                        if (item.haveNext()) {
                            this.delayQueue.add(item);
                        }
                    } else {
                        //购买的
                        Integer openMin = item.getOpenMin();
                        this.deviceBuyControlService.open(item.getDeviceId(), openMin * 60);
                        if (item.haveNext()) {
                            this.delayQueue.add(item);
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

}
